package com.ruoyi.vehicle.entity;
import com.ruoyi.vehicle.entity.request.AuthMsg;
import com.ruoyi.vehicle.entity.request.HeartMsg;
import com.ruoyi.vehicle.entity.request.LocationMsg;
import com.ruoyi.vehicle.entity.request.RegisterMsg;
import com.ruoyi.vehicle.utils.BCD8421Operater;
import com.ruoyi.vehicle.utils.BitOperator;
import com.ruoyi.vehicle.utils.JT808ProtocolUtils;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;


/**
 * @author : 琼宇
 * @date : 2024-09-12 20:33
 * @description :
 **/
public class MsgDecoder {

    private static final Logger log = LoggerFactory.getLogger(MsgDecoder.class);

    private BitOperator bitOperator;
    private BCD8421Operater bcd8421Operater;

    public MsgDecoder() {
        this.bitOperator = new BitOperator();
        this.bcd8421Operater = new BCD8421Operater();
    }

    //字节数组到消息体实体类
    public PackageData queueElement2PackageData(byte[] data) throws Exception {
        PackageData ret = new PackageData();

        // 1. 17byte 或 21byte 消息头
        PackageData.MsgHeader msgHeader = this.parseMsgHeaderFromBytes(data);
        ret.setMsgHeader(msgHeader);

        int msgBodyByteStartIndex = 17;
        // 2. 消息体
        // 有子包信息,消息体起始字节后移四个字节:消息包总数(word(16))+包序号(word(16))
        if (msgHeader.isHasSubPackage()) {
            msgBodyByteStartIndex = 21;
        }

        byte[] tmp = new byte[msgHeader.getMsgBodyLength()];
        System.arraycopy(data, msgBodyByteStartIndex, tmp, 0, tmp.length);
        ret.setMsgBodyBytes(tmp);

        // 3. 去掉分隔符之后，最后一位就是校验码
        // int checkSumInPkg =
        // this.bitOperator.oneByteToInteger(data[data.length - 1]);


        //还原报文转义    7D01--->7D   7D02--->7E
        JT808ProtocolUtils jt808ProtocolUtils = new JT808ProtocolUtils();
        byte[] bytes = jt808ProtocolUtils.doEscape4Receive(data, 0, data.length);


        int checkSumInPkg = bytes[bytes.length - 1];



        int calculatedCheckSum = this.bitOperator.getCheckSum4JT808(bytes, 0, bytes.length - 1);
        ret.setCheckSum(checkSumInPkg);
        if (checkSumInPkg != calculatedCheckSum) {
            log.warn("检验码不一致,flowId:{},pkg:{},calculated:{}", msgHeader.getFlowId(), checkSumInPkg, calculatedCheckSum);
        }
        return ret;
    }

    public PackageData.MsgHeader parseMsgHeaderFromBytes(byte[] data) {
        PackageData.MsgHeader msgHeader = new PackageData.MsgHeader();

        // 1. 消息ID word(16)
        // byte[] tmp = new byte[2];
        // System.arraycopy(data, 0, tmp, 0, 2);
        // msgHeader.setMsgId(this.bitOperator.twoBytesToInteger(tmp));
        msgHeader.setMsgId(this.parseIntFromBytes(data, 0, 2));

        // 2. 消息体属性 word(16)=================>
        // System.arraycopy(data, 2, tmp, 0, 2);
        // int msgBodyProps = this.bitOperator.twoBytesToInteger(tmp);
        int msgBodyProps = this.parseIntFromBytes(data, 2, 2);
        msgHeader.setMsgBodyPropsField(msgBodyProps);
        // [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度)
        msgHeader.setMsgBodyLength(msgBodyProps & 0x1ff);
        // [10-12] 0001,1100,0000,0000(1C00)(加密类型)
        msgHeader.setEncryptionType((msgBodyProps & 0xe00) >> 10);
        // [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包)
        msgHeader.setHasSubPackage(((msgBodyProps & 0x2000) >> 13) == 1);
        // [14-15] 1100,0000,0000,0000(C000)(保留位)
        msgHeader.setReservedBit(((msgBodyProps & 0xc000) >> 14) + "");
        // 消息体属性 word(16)<=================

        msgHeader.setVersion(this.parseIntFromBytes(data, 4,1));


        // 3. 终端手机号 bcd[10]
        // tmp = new byte[10];
        // System.arraycopy(data, 4, tmp, 0, 6);
        // msgHeader.setTerminalPhone(this.bcd8421Operater.bcd2String(tmp));
        msgHeader.setTerminalPhone(this.parseBcdStringFromBytes(data, 5, 10));

        // 4. 消息流水号 word(16) 按发送顺序从 0 开始循环累加
        // tmp = new byte[2];
        // System.arraycopy(data, 10, tmp, 0, 2);
        // msgHeader.setFlowId(this.bitOperator.twoBytesToInteger(tmp));
        msgHeader.setFlowId(this.parseIntFromBytes(data, 15, 2));

        // 5. 消息包封装项
        // 有子包信息
        if (msgHeader.isHasSubPackage()) {
            // 消息包封装项字段
            msgHeader.setPackageInfoField(this.parseIntFromBytes(data, 17, 4));
            // byte[0-1] 消息包总数(word(16))
            // tmp = new byte[2];
            // System.arraycopy(data, 12, tmp, 0, 2);
            // msgHeader.setTotalSubPackage(this.bitOperator.twoBytesToInteger(tmp));
            msgHeader.setTotalSubPackage(this.parseIntFromBytes(data, 17, 2));

            // byte[2-3] 包序号(word(16)) 从 1 开始
            // tmp = new byte[2];
            // System.arraycopy(data, 14, tmp, 0, 2);
            // msgHeader.setSubPackageSeq(this.bitOperator.twoBytesToInteger(tmp));
            msgHeader.setSubPackageSeq(this.parseIntFromBytes(data, 19, 2));
        }
        return msgHeader;
    }

    public String parseStringFromBytes(byte[] data, int startIndex, int lenth) {
        return this.parseStringFromBytes(data, startIndex, lenth, null);
    }

    public String parseStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) {
        try {
            byte[] tmp = new byte[lenth];
            System.arraycopy(data, startIndex, tmp, 0, lenth);
            return new String(tmp, "GBK");
        } catch (Exception e) {
            log.error("解析字符串出错:{}", e.getMessage());
            e.printStackTrace();
            return defaultVal;
        }
    }

    public String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth) {
        return this.parseBcdStringFromBytes(data, startIndex, lenth, null);
    }

    public String parseBcdStringFromBytes(byte[] data, int startIndex, int lenth, String defaultVal) {
        try {
            byte[] tmp = new byte[lenth];
            System.arraycopy(data, startIndex, tmp, 0, lenth);
            return this.bcd8421Operater.bcd2String(tmp);
        } catch (Exception e) {
            log.error("解析BCD(8421码)出错:{}", e.getMessage());
            e.printStackTrace();
            return defaultVal;
        }
    }

    public int parseIntFromBytes(byte[] data, int startIndex, int length) {
        return this.parseIntFromBytes(data, startIndex, length, 0);
    }

    public int parseIntFromBytes(byte[] data, int startIndex, int length, int defaultVal) {
        try {
            // 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃
            final int len = length > 4 ? 4 : length;
            byte[] tmp = new byte[len];
            System.arraycopy(data, startIndex, tmp, 0, len);
            return bitOperator.byteToInteger(tmp);
        } catch (Exception e) {
            log.error("解析整数出错:{}", e.getMessage());
            e.printStackTrace();
            return defaultVal;
        }
    }

    public AuthMsg toAuthMsg(PackageData jt808Msg) {
        AuthMsg ret = new AuthMsg(jt808Msg);
        byte[] data = ret.getMsgBodyBytes();

        AuthMsg.AuthInfo body = new AuthMsg.AuthInfo();

        body.setLength(this.parseIntFromBytes(data, 0,1 ));
        body.setReplyToken(this.parseStringFromBytes(data, 1, body.getLength() ));
        body.setImei(this.parseStringFromBytes(data, 1+ body.getLength(), 15));
        body.setVersion(this.parseStringFromBytes(data, 16+ body.getLength(), 20));

        ret.setAuthInfo(body);
        return ret;
    }

    public LocationMsg toLocationMsg(PackageData jt808Msg) {
        LocationMsg ret = new LocationMsg(jt808Msg);
        byte[] data = ret.getMsgBodyBytes();

        LocationMsg.LocationInfo body = new LocationMsg.LocationInfo();

        body.setWarningFlag(this.parseIntFromBytes(data, 0, 4));
        body.setStatus(this.parseIntFromBytes(data, 4,4 ));
        body.setLatitude(this.parseIntFromBytes(data, 8, 4));
        body.setLongitude(this.parseIntFromBytes(data, 12, 4));
        body.setHigh(this.parseIntFromBytes(data, 16, 2));
        body.setSpeed(this.parseIntFromBytes(data, 18, 2));
        body.setDirection(this.parseIntFromBytes(data , 20, 2));
        body.setTime(this.parseBcdStringFromBytes(data, 22, 6));

        ret.setLocationInfo(body);
        return ret;
    }


    public RegisterMsg toRegisterMsg(PackageData jt808Msg) {
        RegisterMsg ret = new RegisterMsg(jt808Msg);
        byte[] data = ret.getMsgBodyBytes();

        RegisterMsg.RegisterInfo body = new RegisterMsg.RegisterInfo();

        // 1. byte[0-1] 省域ID(WORD)
        // 设备安装车辆所在的省域，省域ID采用GB/T2260中规定的行政区划代码6位中前两位
        // 0保留，由平台取默认值
        body.setProvinceId(this.parseIntFromBytes(data, 0, 2));

        // 2. byte[2-3] 设备安装车辆所在的市域或县域,市县域ID采用GB/T2260中规定的行 政区划代码6位中后四位
        // 0保留，由平台取默认值
        body.setCityId(this.parseIntFromBytes(data, 2, 2));

        // 3. byte[4-14] 制造商ID(BYTE[11]) 11 个字节，终端制造商编码
        // byte[] tmp = new byte[5];
        body.setManufacturerId(this.parseStringFromBytes(data, 4, 11));

        // 4. byte[15-44] 终端型号(BYTE[30]) 30个字节， 此终端型号 由制造商自行定义 位数不足八位的，补空格。
        body.setTerminalType(this.parseStringFromBytes(data, 15, 30));

        // 5. byte[45-74] 终端ID(BYTE[30]) 30个字节， 由大写字母 和数字组成， 此终端 ID由制造 商自行定义
        body.setTerminalId(this.parseStringFromBytes(data, 45, 30));

        // 6. byte[75] 车牌颜色(BYTE) 车牌颜 色按照JT/T415-2006 中5.4.12 的规定
        body.setLicensePlateColor(this.parseIntFromBytes(data, 75, 1));

        // 7. byte[76-x] 车牌(STRING) 公安交 通管理部门颁 发的机动车号牌
        body.setLicensePlate(this.parseStringFromBytes(data, 76, data.length - 76));

        ret.setRegisterInfo(body);
        return ret;
    }

    public HeartMsg toHeartMsg(PackageData jt808Msg) {
        HeartMsg ret = new HeartMsg(jt808Msg);
        return ret;
    }
}
